package com.bestcem.xm.om.service.impl;

import cn.hutool.core.lang.ObjectId;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.bp.xm.user.grpc.v1.services.Organization;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.om.dao.*;
import com.bestcem.xm.om.entity.*;
import com.bestcem.xm.om.enums.PackageCategoryEnum;
import com.bestcem.xm.om.enums.UserModuleCategoryEnum;
import com.bestcem.xm.om.grpc.client.OmOrgGrpcService;
import com.bestcem.xm.om.service.UserPackService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.xm.om.constant.RedisKeyConstant.USER_PACK_PERM;

/**
 * (UserPack)表服务实现类
 *
 * @author makejava
 * @since 2022-04-01 18:45:54
 */
@Slf4j
@Service("userPackService")
public class UserPackServiceImpl implements UserPackService {
    public static final String STRUCT_KEY = "app:om:pack:struct";
    @Resource
    private OmUserPackDao omUserPackDao;
    @Resource
    private PackMiddleDao packMiddleDao;
    @Resource
    private UserModulePackDao userModulePackDao;
    @Resource
    private UserDomainDao userDomainDao;
    @Resource
    private UserSubmoduleDao userSubmoduleDao;
    @Resource
    private UserMmoduleDao userMmoduleDao;
    @Resource
    private PlatformDao platformDao;
    @Resource
    private RedisService redisUtil;
    @Resource
    private OmOrgGrpcService omOrgGrpcService;


    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public UserPack queryById(String id) {
        return omUserPackDao.getById(id);
    }

    /**
     * 新增数据
     *
     * @param userPack 实例对象
     * @return 实例对象
     */
    @Override
    public UserPack insert(UserPack userPack) {
        this.omUserPackDao.insert(userPack);
        return userPack;
    }

    /**
     * 修改数据
     *
     * @param userPack 实例对象
     * @return 实例对象
     */
    @Override
    public UserPack update(UserPack userPack) {
        omUserPackDao.update(userPack);
        return this.queryById(userPack.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String id) {
        return omUserPackDao.deleteById(id) > 0;
    }

    @Override
    public ServiceResult<List<UserPack>> findByType(Integer type) {
        List<UserPack> userPacks = omUserPackDao.findByType(type);
        if (CollectionUtils.isEmpty(userPacks)) {
            return ServiceResult.fail("找不到该套餐");
        }
        return ServiceResult.success(userPacks);
    }

    @Override
    public Boolean hasPackageDomain(String packageId, String domainCode) {
        if (ObjectId.isValid(packageId) && StringUtils.isNotEmpty(domainCode)) {
            UserPack pack = omUserPackDao.getById(packageId);
            if (Objects.nonNull(pack)) {
                UserDomain domain = userDomainDao.findOneByCode(domainCode);
                if (Objects.nonNull(domain)) {
                    UserModulepack userModulepack = new UserModulepack();
                    userModulepack.setPackId(packageId);
                    userModulepack.setModuleId(domain.getId());
                    return userModulePackDao.count(userModulepack) > 0;
                }
            }
        }
        return Boolean.FALSE;
    }

    @Override
    public ServiceResult<String> getPackageQuota(String packId, String orgId) {
        // 如果id为空，则以机构id查出的套餐id为准
        if (StringUtils.isEmpty(packId)) {
            // 查询租户信息
            Organization org = omOrgGrpcService.getByIdOrCode(orgId);
            if (Objects.isNull(org)) {
                return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "机构不存在");
            }
            packId = org.getPackageId();
        }
        UserPack userPack = omUserPackDao.getById(packId);
        if (Objects.isNull(userPack)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "套餐不存在");
        }

        Map<String, Object> resultMap = new HashMap<>(16);
        resultMap.put("pack_perm", getPackStruct(packId));
        resultMap.put("rspd_quota", userPack.getSurveyQuota());
        resultMap.put("project_quota", userPack.getProjectQuota());
        resultMap.put("user_quota", userPack.getUserQuota());
        resultMap.put("member_ind_quota", userPack.getMemberIndQuota());
        resultMap.put("datasource_quota", userPack.getBiDatasourceQuota());
        resultMap.put("member_group_quota", userPack.getMemberGroupQuota());
        return ServiceResult.success(JSON.toJSONString(resultMap));
    }

    @Override
    public ServiceResult<List<String>> listPackageIdsByCode(String code, Integer category) {
        String id = "";
        switch (PackageCategoryEnum.getByType(category)) {
            case MODULE:
                UserMmodule mmodule = userMmoduleDao.findOneByCode(code);
                if (Objects.nonNull(mmodule)) {
                    id = mmodule.getId();
                }
                break;
            case SUBMODULE:
                UserSubmodule submodule = userSubmoduleDao.findOneByCode(code);
                if (Objects.nonNull(submodule)) {
                    id = submodule.getId();
                }
                break;
            case DOMAIN:
                UserDomain domain = userDomainDao.findOneByCode(code);
                if (Objects.nonNull(domain)) {
                    id = domain.getId();
                }
                break;
            default:
        }
        UserModulepack userModulepack = new UserModulepack();
        userModulepack.setModuleId(id);
        userModulepack.setCategory(category);
        List<UserModulepack> userModulepacks = userModulePackDao.queryAllByLimit(userModulepack);
        List<String> packIdList = userModulepacks.stream().map(UserModulepack::getPackId).distinct().collect(Collectors.toList());
        return ServiceResult.success(packIdList);
    }

    @Override
    public ServiceResult<String> getPackageIdByPlatformCodeAndPackageName(String platformCode, String packageName) {
        OmPlatform omPlatform = platformDao.findOneByPlatformCode(platformCode);
        if (Objects.isNull(omPlatform)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "合作商信息不存在");
        }
        UserPack pack = omUserPackDao.getByName(packageName);
        if (Objects.isNull(pack)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "套餐不存在");
        }
        PackMiddle packMiddle = packMiddleDao.findOneByPlatformIdAndPackageId(omPlatform.getId(), pack.getId());
        if (Objects.isNull(packMiddle)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "合作商对应套餐不存在");
        }
        return ServiceResult.success(pack.getId());
    }

    /**
     * 删除套餐缓存
     *
     * @param orgId
     * @return
     */
    @Override
    public ServiceResult<String> deletePackageCacheByOrgId(String orgId) {
        // 删除套餐缓存
        redisUtil.del(String.format(USER_PACK_PERM, orgId));
        return ServiceResult.success();
    }

    private Map<String, JSONObject> getPackStruct(String packId) {
        List<UserModulepack> modulePackList = userModulePackDao.listByPackId(packId);
        Map<Integer, List<String>> idListMap = modulePackList.stream()
                .collect(Collectors.groupingBy(UserModulepack::getCategory,
                        Collectors.mapping(UserModulepack::getModuleId, Collectors.toList())));
        List<String> domainIdList = idListMap.get(PackageCategoryEnum.DOMAIN.getIndex());
        Map<String, List<JSONObject>> domainMap = new HashMap<>(16);
        if (!CollectionUtils.isEmpty(domainIdList)) {
            List<UserDomain> domainList = userDomainDao.listByIds(domainIdList);
            for (UserDomain domain : domainList) {
                List<JSONObject> list = domainMap.getOrDefault(domain.getParentModuleId(), new ArrayList<>());
                JSONObject domainObj = new JSONObject();
                domainObj.put("id", domain.getId());
                domainObj.put("code", domain.getCode());
                domainObj.put("is_quota", domain.getIsQuota());
                list.add(domainObj);
                domainMap.put(domain.getParentModuleId(), list);
            }
        }
        Map<String, List<JSONObject>> userSubModuleMap = new HashMap<>(16);
        List<String> subModuleIdList = idListMap.get(PackageCategoryEnum.SUBMODULE.getIndex());
        if (!CollectionUtils.isEmpty(subModuleIdList)) {
            List<UserSubmodule> subModuleList = userSubmoduleDao.listByIds(subModuleIdList);
            for (UserSubmodule userSubmodule : subModuleList) {
                List<JSONObject> list = userSubModuleMap.getOrDefault(userSubmodule.getParentModuleId(), new ArrayList<>());
                JSONObject subModuleObj = new JSONObject();
                subModuleObj.put("id", userSubmodule.getId());
                subModuleObj.put("code", userSubmodule.getCode());
                subModuleObj.put("Domain", domainMap.getOrDefault(userSubmodule.getId(), new ArrayList<>()));
                list.add(subModuleObj);
                userSubModuleMap.put(userSubmodule.getParentModuleId(), list);
            }
        }
        Map<String, JSONObject> packStructMap = new HashMap<>(16);
        List<String> moduleIdList = idListMap.get(PackageCategoryEnum.MODULE.getIndex());
        if (!CollectionUtils.isEmpty(moduleIdList)) {
            List<UserMmodule> moduleList = userMmoduleDao.listByIds(moduleIdList);
            for (UserMmodule userMmodule : moduleList) {
                JSONObject subModuleObj = new JSONObject();
                subModuleObj.put("id", userMmodule.getId());
                subModuleObj.put("SubModule", userSubModuleMap.getOrDefault(userMmodule.getId(), new ArrayList<>()));
                packStructMap.put(userMmodule.getCode(), subModuleObj);
            }
        }
        return packStructMap;
    }

    private UserModulepack convertToModulePack(String packId, String moduleId, UserModuleCategoryEnum categoryEnum) {
        UserModulepack modulePack = new UserModulepack();
        modulePack.setId(ObjectId.next());
        modulePack.setPackId(packId);
        modulePack.setModuleId(moduleId);
        modulePack.setCategory(categoryEnum.getIndex());
        modulePack.setCreateTime(LocalDateTime.now());
        modulePack.setUpdateTime(LocalDateTime.now());
        return modulePack;
    }
}
